classdef HelperCNDREstimatorNWPR < matlab.System
    % HelperCNDREstimatorNWPR 使用窄带-宽带功率比(NWPR)方法估计信号载噪比
    % 
    % 参考文献：
    % [1] Falletti, E., Pini, M., & Lo Presti, L., 
    %     低复杂度GNSS数字接收机的载波噪声比估计算法

    properties
        Tint = 0.001 % 相干积分时间(秒)，必须整除0.02s导航码长
        CNDRGenie           % 用于初始化CNDR的辅助对象
    end

    properties(Nontunable)
        N = 50              % 每次生成一个CNDR估计所需的相干积分输出数
        Tbit = 0.02         % 导航码位持续时间(秒)
    end

    properties(Access = private)
        M                   % 每位包含的样本数
        cndrLast            % 最近一次CNDR估计值(dBHz), 初始假定-160dBW和290K
        bufferrc            % 缓存，用于保存相干积分样本
        countrc             % 当前缓冲区内样本数
    end

    methods(Access = public)
        function obj = HelperCNDREstimatorNWPR(config, rxConfig)
            obj.cndrLast = 0;
            obj.Tint = rxConfig.tracker.totalIntegTime;
            obj.Tbit = config.signal.bitDuration;
        end
    end

    methods(Access = protected)
        function setupImpl(obj)
            % 初始化M、bufferrc等参数
            obj.M = obj.Tbit / obj.Tint; % 计算每比特采样数
            if ~(obj.M > 1 && floor(obj.M) == obj.M)
                obj.M = 5; % 若不合法，自动调整为5
                warning(['NWPR方法采样数已自动调整为 ', num2str(obj.M), ' !'])
            end
            obj.bufferrc = zeros(obj.M, obj.N / obj.M); % 初始化缓存
            obj.countrc = 0;
        end

        function cndr = stepImpl(obj, rc)
            % 算法主流程，用NWPR法估算CNDR
            obj.countrc = obj.countrc + 1;
            obj.bufferrc(obj.countrc) = rc; % 缓存新样本
            if obj.countrc == obj.N % 累积到N后开始估算
                WBP = sum(abs(obj.bufferrc).^2);        % 宽带功率: 所有样本幅度平方和
                NBP = abs(sum(obj.bufferrc)).^2;        % 窄带功率: 所有样本求和取幅度再平方
                mu = obj.M / obj.N * sum(NBP ./ WBP);   % 统计比值
                if mu > 1
                    % 公式：pow2db将线性比值转dBHz
                    obj.cndrLast = pow2db(1 / obj.Tint * (mu - 1) / (obj.M - mu));
                end
                % 移动窗口：移除最旧数据
                obj.bufferrc(:, 1 : end - 1) = obj.bufferrc(:, 2 : end);
                obj.countrc = obj.countrc - obj.M;
            end
            cndr = obj.cndrLast; % 返回CNDR估计值
        end

        function resetImpl(obj)
            % 重置估计器为初始状态
            obj.cndrLast = 0;
            obj.countrc = 0;
        end 
    end
end
